package work.linruchang.util.bean.wrapper.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import work.linruchang.util.EnhanceReflectUtil;
import work.linruchang.util.bean.wrapper.db.SqlFragment;
import work.linruchang.util.bean.wrapper.db.TableInfo;

/**
 *
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2022/01/14
 * @since 1.8
 **/
public class OnWrapperImpl<MasterTable, FirstTable, SecondTable> extends BaseWrapperImpl<FirstTable, SecondTable> {

    QueryWrapperImpl<MasterTable> queryWrapperImpl;

    /**
     * 主表
     */
    protected Class<MasterTable> masterTable;

    /**
     * 是否在原基础上进行拼接
     * true现在仅仅只用于{QueryWrapperImpl#autoJoin(Class[])}方法上
     */
    private boolean joiningAppendFlag = false;

    /**
     * 当前的连表类型
     * 参考{SqlFragment#LEFT_JOIN,SqlFragment#INNER_JOIN,SqlFragment#RIGHT_JOIN}
     */
    private String currentOnjoinSqlFragment = SqlFragment.INNER_JOIN;


    OnWrapperImpl(Class<MasterTable> masterTable, Class<FirstTable> firstTableClazz, Class<SecondTable> secondTableClazz, QueryWrapperImpl<MasterTable> queryWrapperImpl, String currentOnjoinSqlFragment) {
        this(masterTable,firstTableClazz,secondTableClazz, queryWrapperImpl,false, currentOnjoinSqlFragment);
    }

    OnWrapperImpl(Class<MasterTable> masterTable, Class<FirstTable> firstTableClazz, Class<SecondTable> secondTableClazz, QueryWrapperImpl<MasterTable> queryWrapperImpl, boolean joiningAppendFlag, String currentOnjoinSqlFragment) {
        this.masterTable = masterTable;
        this.firstTableClazz = firstTableClazz;
        this.secondTableClazz = secondTableClazz;
        addTable(queryWrapperImpl.getTableInfo(masterTable));
        addTable(queryWrapperImpl.getTableInfo(firstTableClazz));
        addTable(queryWrapperImpl.getTableInfo(secondTableClazz));
        this.queryWrapperImpl = queryWrapperImpl;
        this.joinSqlFragments = queryWrapperImpl.joinSqlFragments;
        this.joiningAppendFlag = joiningAppendFlag;
        this.currentOnjoinSqlFragment = StrUtil.blankToDefault(currentOnjoinSqlFragment,SqlFragment.INNER_JOIN);
    }

    public QueryWrapperImpl<MasterTable> on(String firstTableField, String secondTableField) {
        onBuild(firstTableField, secondTableField, false);
        return queryWrapperImpl;
    }


    public OnWrapperImpl<MasterTable, FirstTable, SecondTable> onAnd(String firstTableField, String secondTableField) {
        return onBuild(firstTableField, secondTableField, true);
    }

    /**
     * on基础上添加条件筛选
     *  例子：  on 主表别名.name = 'xxx'
     * @param dbFieldName  主表的字段
     * @param value 字段值
     * @return
     */
    public QueryWrapperImpl<MasterTable> onEqValue(String dbFieldName, Object value) {
        return onEqValue(masterTable,dbFieldName,value);
    }

    /**
     * on基础上添加条件筛选
     *  例子：  on 主表别名.name = 'xxx'
     * @param tableClazz  表
     * @param dbFieldName  属于表{tableClazz}的字段名
     * @param value 字段值
     * @return
     */
    public QueryWrapperImpl<MasterTable> onEqValue(Class tableClazz, String dbFieldName, Object value) {
        onBuildValue(tableClazz,dbFieldName,value,SqlFragment.WHERE_EQ,false);
        return queryWrapperImpl;
    }
    public OnWrapperImpl<MasterTable, FirstTable, SecondTable> onEqValueAnd(String dbFieldName, Object value) {
        onBuildValue(masterTable,dbFieldName,value,SqlFragment.WHERE_EQ,true);
        return this;
    }
    public OnWrapperImpl<MasterTable, FirstTable, SecondTable> onEqValueAnd(Class tableClazz, String dbFieldName, Object value) {
        onBuildValue(tableClazz,dbFieldName,value,SqlFragment.WHERE_EQ,true);
        return this;
    }



    /**
     * 构建on连表语句
     *
     * @param firstTableField
     * @param secondTableField
     * @param hasAndFlag
     * @return
     */
    private OnWrapperImpl<MasterTable, FirstTable, SecondTable> onBuild(String firstTableField, String secondTableField, boolean hasAndFlag) {
        int joinSqlFragmentsIndex = joinSqlFragments.size() - 1;
        String currentjoinSqlFragment = joinSqlFragments.get(joinSqlFragmentsIndex);
        if(joiningAppendFlag) {
            joinSqlFragmentsIndex = joinSqlFragmentsIndexOf(currentOnjoinSqlFragment, secondTableClazz);
            currentjoinSqlFragment = joinSqlFragments.get(joinSqlFragmentsIndex);
        }



        String sqlTemplate = hasAndFlag ? " ON {} = {} AND " : " ON {} = {} ";
        if (currentjoinSqlFragment.contains("ON")) {
            sqlTemplate = StrUtil.replace(sqlTemplate, "ON", StrUtil.EMPTY);
        }
        if(joiningAppendFlag) {
            TableInfo secondTableInfo = getTableInfo(secondTableClazz);
            String joinSqlPrefix = StrUtil.format(" {} {} AS {} ", currentOnjoinSqlFragment, secondTableInfo.getTableName(), secondTableInfo.getTableAlias());
            if(currentjoinSqlFragment.length() > joinSqlPrefix.length() && !StrUtil.endWithAny(currentjoinSqlFragment, "AND")) {
                sqlTemplate = StrUtil.addPrefixIfNot(sqlTemplate, " AND");
            }
        }


        String firstColumnNameSQL = getColumnAddTableAlias(getFirstTableClazz(), firstTableField);
        String secondColumnNameSQL = getColumnAddTableAlias(getSecondTableClazz(), secondTableField);

        String onSql = StrUtil.format(sqlTemplate, firstColumnNameSQL, secondColumnNameSQL);

        //queryWrapper.getSqlSB().append(onSql);
        String joinSql = currentjoinSqlFragment + onSql;
        joinSqlFragments.set(joinSqlFragmentsIndex, joinSql);

        return this;
    }


    /**
     * 构建on连表语句 == 条件语句
     *
     * @param tableClazz
     * @param dbFieldName
     * @param value
     * @param symbol 参考 {SqlFragment#WHERE_EQ}
     * @param hasAndFlag
     * @return
     */
    private OnWrapperImpl<MasterTable, FirstTable, SecondTable> onBuildValue(Class tableClazz, String dbFieldName, Object value, String symbol, boolean hasAndFlag) {
        Assert.isFalse(StrUtil.equals(symbol,SqlFragment.WHERE_BETWEEN_AND), "当前工具类在on上不支持SQL片段{}, 请剔除", SqlFragment.WHERE_BETWEEN_AND);


        int joinSqlFragmentsIndex = joinSqlFragments.size() - 1;
        String currentjoinSqlFragment = joinSqlFragments.get(joinSqlFragmentsIndex);
        if(joiningAppendFlag) {
            joinSqlFragmentsIndex = joinSqlFragmentsIndexOf(currentOnjoinSqlFragment, secondTableClazz);
            currentjoinSqlFragment = joinSqlFragments.get(joinSqlFragmentsIndex);
        }

        String sqlTemplate = hasAndFlag ? " ON "+ symbol +" AND " : " ON "+ symbol +" ";
        if (currentjoinSqlFragment.contains("ON")) {
            sqlTemplate = StrUtil.replace(sqlTemplate, "ON", StrUtil.EMPTY);
        }
        if(joiningAppendFlag) {
            TableInfo secondTableInfo = getTableInfo(secondTableClazz);
            String joinSqlPrefix = StrUtil.format(" {} {} AS {} ", currentOnjoinSqlFragment, secondTableInfo.getTableName(), secondTableInfo.getTableAlias());
            if(currentjoinSqlFragment.length() > joinSqlPrefix.length() && !StrUtil.endWithAny(currentjoinSqlFragment, "AND")) {
                sqlTemplate = StrUtil.addPrefixIfNot(sqlTemplate, " AND");
            }
        }


        String firstColumnNameSQL = getColumnAddTableAlias(tableClazz, dbFieldName);
        String onSql = StrUtil.format(sqlTemplate, firstColumnNameSQL);
        queryWrapperImpl.joinOnSqlParams.add(value);
        queryWrapperImpl.joinOnSqlParamsTypes.add(EnhanceReflectUtil.getDBColumnNameClassType(tableClazz, dbFieldName));


        //queryWrapper.getSqlSB().append(onSql);
        String joinSql = currentjoinSqlFragment + onSql;
        joinSqlFragments.set(joinSqlFragments.size() - 1, joinSql);

        return this;
    }


}
